﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Serialization;

namespace d39
{
    [Serializable]
    public class Segment
    {
        [XmlIgnore]
        public List<HalfCoordinate> Coordinates { get; set; }

        [XmlAttribute("coords")]
        public string CoordinatesString
        {
            get { return string.Join(" ", from coord in Coordinates select coord.ToHumanReadableString()); }
            set { Coordinates = (from coord in value.Split(' ') select HalfCoordinate.ParseHumanReadable(coord)).ToList(); }
        }

        [XmlIgnore]
        public LayerSet Layers { get; set; }

        [XmlAttribute("layers")]
        public string LayersString
        {
            get { return Layers.ToXmlString(); }
            set { Layers = LayerSet.FromXmlString(value); }
        }

        public Segment()
        {
            Layers = new LayerSet(1);
            Coordinates = new List<HalfCoordinate>();
        }

        public Segment(IEnumerable<HalfCoordinate> coords)
            : this()
        {
            if (coords.Count() <= 1) throw new ArgumentException("Segment must contain at least two points");
            this.Coordinates.AddRange(coords);
        }

        public void Shift(Vector v)
        {
            for (int i = 0; i < Coordinates.Count; i++)
            {
                Coordinates[i] += v;
            }
        }

        public static Segment Parse(string str, int start, out int end)
        {
            var coords = new List<HalfCoordinate>();
            end = start;
            while (Base26Point5.IsValidChar(str, end))
            {
                coords.Add(HalfCoordinate.Parse(str, end, out end));
            }
            if (end < str.Length && str[end++] != '.') throw new ArgumentException("Unterminated segment");
            return new Segment(coords);
        }

        public override string ToString()
        {
            return string.Join("", Coordinates);
        }
    }
    public static class Segments
    {
        public static List<Segment> ParseSegments(string str)
        {
            str = str.TrimEnd('.'); // Handle old segments that had a redundant ".." at the end
            var result = new List<Segment>();
            var end = 0;
            while (Base26Point5.IsValidChar(str, end))
            {
                result.Add(Segment.Parse(str, end, out end));
            }
            if (end != str.Length) throw new ArgumentException("Illegal character in segments: " + str);
            return result;
        }

        public static string ToSegmentString(this IEnumerable<Segment> segments)
        {
            return string.Join(".", segments);
        }
        public static string ToHumanReadableString(this IEnumerable<Segment> segments)
        {
            return string.Join("\r\n", from segment in segments select string.Join(", ", from point in segment.Coordinates select point.ToHumanReadableString()));
        }
        public static List<Segment> ParseHumanReadableSegments(string str)
        {
            return (from line in str.Split('\n')
                   where line.Trim() != ""
                   select new Segment((from point in line.Split(',') select HalfCoordinate.ParseHumanReadable(point.Trim())).ToList())).ToList();
        }
    }
}